#include "bib_Log.h"
#include "bib_Socket.h"

#include <stdlib.h>
#include <stdint.h>

typedef struct EST_CHS{	/*Todos tienen un valor minimo de cero para definir una posicion y un valor minimo de uno para definir el tamanio del disco*/
	uint16_t	cilindro;
	uint16_t	cabezal;
	uint16_t	sector;
} EST_CHS;

typedef struct EST_PLANIFICACION{
	/*uint16_t	cantSectoresDisco;*/
	uint16_t	tamanioCola;
	uint16_t	cantSectoresRecorridos;
	uint32_t	posicionActual;
	uint32_t	sectorSolicitado;
	double		tiempoConsumido;
	uint32_t	proximoSector;
} EST_PLANIFICACION;

#define LECTURA		1
#define ESCRITURA	2
#define PRUEBA		3
#define CANT_SECT	4
#define POSICION	5
#define SALIR		6
#define RTA_ERROR	10

#define CANT_VUELTAS		1
#define CANT_SECT_REC		3

int crearHijoConsola(void);

char nivelLog;

int main(void){

	int sockEscuchaConsola;
	int sockConsola;
	char flagConsola;
	struct sockaddr address;
	char *payload;
	struct HEADER_NIPC header;
	struct EST_CHS poscicionCabezal;
	uint32_t id;
	int i;
	struct EST_PLANIFICACION planif;
	uint32_t *sectoresRecorridos;
	char aux[12];
	struct EST_CHS disco;

	disco.cilindro = 1024;
	disco.sector = 1024;

	nivelLog = DEBUG;

	imprimirLog(DEBUG, "La concha de tu mama", "");

	unlink(SERVER_PATH);

	if (!abrirSocketUnix(&sockEscuchaConsola)){
		if ((flagConsola = crearHijoConsola()) == FIN_ERROR){
			cerrarSocket(&sockEscuchaConsola);
			return FIN_ERROR;
		}

		if (flagConsola == FIN_OK)
			flagConsola = aceptarConexion(&sockEscuchaConsola, &sockConsola, &address);

		header.type = TIPO_HANDSHAKE;
		header.payloadLength = sizeof(struct EST_CHS);

		if (enviarMensajeNIPC(sockConsola, &header, (char *) &disco))
			cerrarSocket(&sockConsola);

		cerrarSocket(&sockEscuchaConsola);
	}

	while(1){
		for (i = 0; i < CANT_VUELTAS; i++){
			if (recibirMensajeNIPCDinamico(sockConsola, &header, &payload))
				return FIN_ERROR;
			free(payload);
		}

		if (header.type == ESCRITURA){

			header.type = ESCRITURA/*RTA_ERROR*/;
			header.payloadLength = sizeof(uint32_t);

			id = 0;

			for (i = 0; i < CANT_VUELTAS; i++)
				if (enviarMensajeNIPC(sockConsola, &header, (char *) &id)){
					imprimirLogNumerico(ERROR, "No se pudo responder al pedido:", id);
					break;
				}
		}

		else if (header.type == POSICION){
			poscicionCabezal.cabezal = 6;
			poscicionCabezal.cilindro = 6;
			poscicionCabezal.sector = 6;
			header.payloadLength = sizeof(struct EST_CHS);
			if (enviarMensajeNIPC(sockConsola, &header, (char *) &poscicionCabezal))
				break;
		}

		else if (header.type == PRUEBA){

			/*planif.cantSectoresDisco = 4;*/
			planif.cantSectoresRecorridos = CANT_SECT_REC;
			planif.posicionActual = 0;
			planif.proximoSector = 11;
			planif.sectorSolicitado = 23558;
			planif.tamanioCola = 0;
			planif.tiempoConsumido = 678;

			header.type = PRUEBA;
			header.payloadLength = sizeof(struct EST_PLANIFICACION) + sizeof(uint32_t) * planif.cantSectoresRecorridos;


			sectoresRecorridos = (uint32_t *) malloc(sizeof(uint32_t) * planif.cantSectoresRecorridos);

			for(i = 0; i < planif.cantSectoresRecorridos; i++){
				sectoresRecorridos[i] = i + 6;
			}

			payload = (char *) malloc(header.payloadLength);
			memcpy(payload, (char *) &planif, sizeof(struct EST_PLANIFICACION));
			memcpy(payload + sizeof(struct EST_PLANIFICACION), (char *) sectoresRecorridos, sizeof(uint32_t) * planif.cantSectoresRecorridos);

			/*for(i = 0; i < 36; i++){
				printf("payload %d: %d\n", i, payload[i]);
			}
			memcpy(aux, (char *) sectoresRecorridos, sizeof(uint32_t) * planif.cantSectoresRecorridos);
			for(i = 0; i < 12; i++){
				printf("aux %d: %d\n", i, aux[i]);
			}
			for(i = 0; i < planif.cantSectoresRecorridos; i++)
				printf("Dir. Logica:%d\n", *(sectoresRecorridos + i));*/

			for(i = 0; i < CANT_VUELTAS; i++){

				imprimirLog(DEBUG, "A enviar se ha dicho", "");
				if (enviarMensajeNIPC(sockConsola, &header, payload)){
					imprimirLog(ERROR, "No se pudo responder al trace", "");
					free(sectoresRecorridos);
					free(payload);
					return FIN_ERROR;
				}
				imprimirLog(DEBUG, "Envio OK", "");
			}
			free(sectoresRecorridos);
			free(payload);

		}

		else if (header.type == SALIR)
			break;
	}

	cerrarSocket(&sockConsola);

	unlink(SERVER_PATH);

	return FIN_OK;
}
/*=====================================================================================*/
int crearHijoConsola(void){

	pid_t pid;

	if ((pid = fork()) == -1){
		imprimirLog(WARNING, "No se pudo crear el hijo consola.", "");
		return FIN_WARNING;
	}

	if (!pid)
		if (execl("./Consola/consolaPPD", "", NULL) == -1){
			imprimirLog(ERROR, "execl:", strerror(errno));
			return FIN_ERROR;
		}

	return FIN_OK;
}
